/* ******************************************************************************
* 2019 - present Contributed by Apulis Technology (Shenzhen) Co. LTD
*
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available at
* https://www.opensource.org/licenses/MIT
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: MIT
***************************************************************************** */
package jobscheduler

import (
	"fmt"
	"encoding/json"
)

type Container struct {

	// container data
	ContainerName   string `json:"containerName"`
	ImageName    	string `json:"imageName"`
	Cmd          	[]string `json:"cmd"`
	MountPoints  	[]MountPoint `json:"mountPoints"`
	ResourceQuota 	ResourceQuota `json:"resourceQuota"`
	Envs 			map[string]string `json:"envs"`
	Ports           []ContainerPort `json:"ports"`
}

func NewContainer() *Container {
	return &Container{
		Cmd:             make([]string, 0),
		Envs:            make(map[string]string),
		MountPoints:     make([]MountPoint, 0),
	}
}

func (c *Container) SetCmd(cmd []string) *Container  {
	c.Cmd = cmd
	return c
}

func (c *Container) GetCmd() []string {
	return c.Cmd
}

func (c *Container) SetImage(image string) *Container  {
	c.ImageName = image
	return c
}

func (c *Container) GetImage() string {
	return c.ImageName
}

func (c *Container) Valid() (bool, string) {

	if len(c.GetCmd()) == 0 {
		return false, fmt.Sprintf("empty command")
	}

	return true, ""
}

func (c *Container) SetMounts(mounts []MountPoint) *Container  {
	c.MountPoints = mounts
	return c
}

func (c *Container) GetMounts() []MountPoint {
	return c.MountPoints
}

func (c *Container) ToString() string {
	data, _ := json.Marshal(*c)
	return string(data)
}

func (c *Container) FromString(data string) error {
	return json.Unmarshal([]byte(data), c)
}

func (c *Container) GetEnvs() map[string]string {
	return c.Envs
}

func (c *Container) SetEnvs(envs map[string]string) {
	c.Envs = envs
}

func (c *Container) SetContainerName(name string) {
	c.ContainerName = name
}

func (c *Container) GetContainerName() string {
	return c.ContainerName
}

func (c *Container) GetResourceQuota() ResourceQuota {
	return c.ResourceQuota
}

func (c *Container) GetPorts() []ContainerPort {
	return c.Ports
}

type JobAffinity struct {
	JobId string `json:"jobId"`
	TaskName string `json:"taskName"`
}

func (a *JobAffinity) Valid() bool {

	if len(a.JobId) == 0 {
		return false
	}

	return true
}

func (a *JobAffinity) GetJobId() string {
	return a.JobId
}

func (a *JobAffinity) GetTaskName() string {
	return a.TaskName
}

func (a *JobAffinity) GetAffinityLabels() map[string]string {

	var value string

	if len(a.GetTaskName()) > 0 {
		value = fmt.Sprintf("%s-%s", a.GetJobId(), a.GetTaskName())
	} else {
		value = a.GetJobId()
	}

	return map[string]string{
		"task-affinity" : value,
	}
}

type Affinity struct {
	PodAffinity *PodAffinity
}

type PodAffinity struct {
	RequiredDuringSchedulingIgnoredDuringExecution []PodAffinityTerm
}

type PodAffinityTerm struct {
	LabelSelector *LabelSelector `json:"labelSelector"`
	Namespaces []string `json:"namespaces"`
	TopologyKey string `json:"topologyKey"`
}

type LabelSelector struct {
	MatchLabels map[string]string `json:"matchLabels"`
}

func (a *Affinity) Empty() bool {

	if a.PodAffinity != nil {
		if len(a.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution) > 0 {
			if len(a.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].LabelSelector.MatchLabels) > 0 {
				return false
			}
		}
	}

	return true
}

func (a *Affinity) GetFirstMatchLabels() map[string]string {


	if a.PodAffinity != nil {
		if len(a.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution) > 0 {
			if a.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].LabelSelector != nil {
				if len(a.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].LabelSelector.MatchLabels) > 0 {
					return a.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].LabelSelector.MatchLabels
				}
			}
		}
	}

	return nil
}

type MetaData struct {
	Annotations map[string]string `json:"annotations"`
}

func (m* MetaData) GetAnnotations() map[string]string {
	return m.Annotations
}

func (m* MetaData) SetAnnotations(anno map[string]string) {
	m.Annotations = anno
}


func (m* MetaData) DisableIstio() {

	annotation := m.GetAnnotations()
	if annotation == nil {
		annotation = make(map[string]string)
	}

	annotation["sidecar.istio.io/inject"] = "false"
	m.SetAnnotations(annotation)
}






